home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
presto
/
presto10.lha
/
src
/
threads.h
< prev
next >
Wrap
C/C++ Source or Header
|
1991-12-11
|
7KB
|
255 lines
#ifndef __presto__threads_h__
#define __presto__threads_h__
class SynchroObject;
class Process;
class Thread;
class ThreadQ;
class Scheduler;
class Callstate;
extern Thread *systhread;
extern private_t Thread *thisthread; // always refers to running thread
extern Process* thisproc;
#define TF_SCHEDULER 0x01 /* special thread. Loops only */
#define TF_KEEPSTACK 0x02 /* dont init stack on runrun */
#define TF_INCOMPLETE 0x04 /* must acquire a stack before run */
#define TF_NONPREEMPTABLE 0x08 /* can not preempt */
#define TF_WILLJOIN 0x20 /* someone will join on it */
#define TS_IDLE 0x01 /* useful, but not started */
#define TS_RUNNING 0x02 /* busy */
#define TS_READY 0x04 /* living in the readyq */
#define TS_BLOCKED 0x20 /* blocked. Don't care on what */
#define TS_LOCKED 0x80 /* unused */
#define TS_STOPPED 0x100 /* thread is unconditionally stopped */
#define TS_VIRGIN 0x400 /* thread not yet begun */
#define TS_ERROR 0x800 /* something amiss */
#define TS_DELETE 0x1000 /* no more trips to bed */
//
// FINISHED should be part of the flags and not the state.
//
#define TS_FINISHED 0x2000 /* all done */
#define TS_ANY (~0) /* matches all */
#define TP_BASEPRIO 0 /* base priority */
//
// WARNING: A CHANGE TO THIS CLASS OR ANY OF ITS BASE CLASSES MAY REQUIRE
// RECOMPUTING THE STRUCT OFFSETS USED IN swtch!!
//
class Stack;
class Thread : public Object {
protected:
// *** The offsets of t_csp, t_fp and t_proc are known to swtch().
int *t_csp; // current stack pointer
int *t_fp; // frame pointer
Process *t_proc; // who is running me now
#ifdef FPU_PREEMPT
// *** The offset of t_usingfpu is also known to swtch().
int t_usingfpu;
#endif /* FPU_PREEMPT */
Stack *t_stack; // thread's stack
int t_stack_size; // size of stack
int t_state; // current state
int t_flags; // internal only flags
#ifdef sun
int t_pc;
#endif /* sun */
#ifdef vax
int t_pc; // needed for Ultrix preemption
#endif /* vax */
#ifdef PROFILE
int qThread;
#endif
int t_tag; // given tag on birth (UNIQUE)
int t_tid; // user's tag name
int t_pri; // thread priority
int t_expired; // true iff timeslice expired
int t_slockcount; // number of spinlocks held/spinning
Objany t_data; // for getdata/setdata
Objany t_boundobj; // what we are bound to
Callstate t_callstate; // initial call state
SynchroObject *t_blockedon; // Synchro object we are blked on
// redo
union {
Thread* thread; // thread waiting
Objany value; // ready value
} ut_join;
#define t_jthread ut_join.thread
#define t_jvalue ut_join.value
virtual void t_start1(Objany obj); // second half of fork/start
public:
Thread(char* name=0, int tid = 0, long ssiz = DEFSTACKSIZ);
Thread(int tid);
virtual Thread* newthread(char* name=0, int tid = 0, // vtl ctr
long ssiz = DEFSTACKSIZ);
void *operator new(size_t);
void operator delete(void *);
virtual ~Thread(); // nuke a thread
#define NOJOIN 0
#define WILLJOIN TF_WILLJOIN
#ifdef mips
/* Mips does not support var args well. */
virtual int start(Objany obj, PFany pf, Objany arg = 0);
// Usage: thisthread->fork({NO,WILL}JOIN, ...)
virtual Thread* fork(int needjoin, Objany obj, PFany pf,
Objany arg = 0);
#else
virtual int start(Objany obj, PFany pf, ...); // enqueue
// Usage: thisthread->fork({NO,WILL}JOIN, ...)
virtual Thread* fork(int needjoin, Objany obj, PFany pf, ...);
#endif /* mips */
virtual int runrun(); // LIFE STARTS HERE
virtual int run();
void swtch(); // back to the sched thread
virtual void sleep(SynchroObject* so = 0); // relinquish
virtual void wakeup(SynchroObject* so = 0); // resume
virtual void willjoin(); // want to join
virtual Objany join(); // please join
virtual void terminate(Objany retobj=0); // thread is finished
// virtual void setaffinity(Process* p); // mark affinity
void setdata(Objany data)
{ t_data = data; }
Objany getdata()
{ return t_data; }
void setstate(int newstate)
{ t_state = newstate; }
void orstate(int st)
// { ATOMIC_ORL(&t_state, st); }
{ t_state |= st; }
void andstate(int st)
// { ATOMIC_ANDL(&t_state, st); }
{ t_state &= st; }
void isready()
{ orstate(TS_READY); }
void setflags(int newflags)
{ t_flags = newflags; }
void holdingspinlock()
{ t_slockcount++; }
void releasingspinlock()
{ t_slockcount--; }
int inspinlock()
{ return(t_slockcount); }
inline Stack *stack();
int *csp()
{ return t_csp; }
int flags()
{ return t_flags; }
#ifdef sun
void setpc(int pc)
{t_pc = pc;}
int getpc()
{return t_pc;}
#endif /* sun */
#ifdef vax
void setpc(int pc)
{t_pc = pc;}
int getpc()
{return t_pc;}
#endif /* vax */
int state()
{ return t_state; }
int tag()
{ return t_tag; }
int tid()
{ return t_tid; }
void setpri(int newpri) // beware of multiple writers
{ t_pri= newpri; }
int getpri()
{ return t_pri; }
void setproc(Process* p)
{ t_proc = p; }
Process *getproc()
{ return t_proc; }
Process **proc()
{ return &t_proc; }
inline void isrunning(); // mark thread running
void isrunning2(); // but wait until it is done running
inline void isnotrunning(); // as set by someone else
#ifdef PROFILE
inline int getqThread()
{ return qThread; }
#endif
int stackcnt()
{ return stack()->numstacksbuilt(); }
int tagcnt();
//
// Preemption related cruft
//
void preemptable()
{ t_flags &= ~TF_NONPREEMPTABLE; }
void nonpreemptable()
{ t_flags |= TF_NONPREEMPTABLE; }
int ispreemptable()
{ return ( (t_flags & TF_NONPREEMPTABLE) == 0 ); }
#ifdef FPU_PREEMPT
void usingfpu()
{ t_usingfpu = 1; }
void notusingfpu()
{ t_usingfpu = 0; }
int isusingfpu()
{ return (t_usingfpu); }
#endif /* FPU_PREEMPT */
double cputime(); // in seconds
int canpreempt();
virtual void print(ostream& = cout);
friend class ThreadQ;
friend class ThreadQUnlocked;
};
//
// Mark a thread as running. This should be called before
// runrun. If the thread is already running, the caller will
// wait. This guarantess that we don't have two scheduling threads
// trouncing on this poor thread's stack. One guy coming down
// into runrun, while the other guy is trying to return from it.
// We don't have to lock anything, since there is only one ordering of
// ops on the state that can cause problems,
// and the problems are solved by delaying the
// second thread here.
//
inline void
Thread::isrunning()
{
if (t_state&TS_RUNNING)
(void)isrunning2(); // looping wait
orstate(TS_RUNNING);
}
//
// This should be called after runrun
//
inline void
Thread::isnotrunning()
{
// if not finished, and not running, balk
if ( ((t_state&TS_FINISHED) == 0) && ((t_state&TS_RUNNING)== 0) )
error("Thread is already not running\n");
else
andstate(~TS_RUNNING);
}
inline
Stack*
Thread::stack()
{
if (t_flags&TF_INCOMPLETE)
error("Thread has no stack");
return t_stack;
}
#endif /* __presto__threads_h__ */